// 页面字典
const DICT = {
    POSITION: {
        // 左对齐
        LEFT: "left",
        // 右对齐
        RIGHT: "right",
    }
};
// 模拟接收的杨辉三角层数
const NUM_OF_LAYERS = 13;
// 打印对齐方式, 可以设置的值从字典中看
const POSITION = DICT.POSITION.RIGHT;
// 控制是否补全打印为菱形
const AXIAL_SYMMETRY = false;
// 需要展示的杨辉三角的数
const INDEX = "7 5";


/**
 * 功能: 打印杨辉三角主函数
 * @param numOfLayers   要打印的杨辉三角层数
 * @param position      打印对齐方式控制
 * @param axialSymmetry 是否补全打印为轴对称菱形
 * @param index         要打印的值得坐标信息
 */
function printYangHuiTriangle(numOfLayers, position, axialSymmetry, index) {
    _valid(numOfLayers, index);
    const yangHuiTriangleArray = _generateYangHuiTriangleArray(numOfLayers);
    _innerPrint(yangHuiTriangleArray, position, axialSymmetry, index);
}

/**
 * 功能: 打印杨辉三角, 以更好的形式
 * @param yangHuiTriangleArray  待打印的杨辉三角数据
 * @param position      打印对齐方式控制
 * @param axialSymmetry 是否补全打印为轴对称菱形
 * @param index         要打印的下标的坐标信息
 * @private
 */
function _innerPrint(yangHuiTriangleArray, position, axialSymmetry, index) {
    // length最长的元素长度
    let maxNumberLen = 0;
    // 最后一行数据
    let lastRowData = yangHuiTriangleArray[yangHuiTriangleArray.length - 1];
    // 计算出最长元素的长度
    for (let i = 0; i < lastRowData.length; i++) {
        if ((lastRowData[i] + "").length > maxNumberLen) {
            maxNumberLen = (lastRowData[i] + "").length;
        }
    }

    // 使打印数字间存在一个空格
    maxNumberLen++;

    // 进行对齐打印
    for (let i = 0; i < yangHuiTriangleArray.length; i++) {
        const rowData = yangHuiTriangleArray[i];
        const prefixSpaceArray = _generatePrefixSpace(i + 1, yangHuiTriangleArray.length);
        let printRow = "";

        for (let j = 0; j < prefixSpaceArray.length; j++) {
            printRow += _fill(prefixSpaceArray[j], maxNumberLen, position);
        }

        for (let j = 0; j < rowData.length; j++) {
            printRow += _fill(rowData[j], maxNumberLen, position);
            if (j !== rowData.length - 1) {
                printRow += _fill("", maxNumberLen, position);
            }
        }

        console.log(printRow);
    }

    if (axialSymmetry) {
        // 补全打印为菱形
        for (let i = yangHuiTriangleArray.length - 2; i >= 0; i--) {
            const rowData = yangHuiTriangleArray[i];
            const prefixSpaceArray = _generatePrefixSpace(i + 1, yangHuiTriangleArray.length);
            let printRow = "";

            for (let j = 0; j < prefixSpaceArray.length; j++) {
                printRow += _fill(prefixSpaceArray[j], maxNumberLen, position);
            }

            for (let j = 0; j < rowData.length; j++) {
                printRow += _fill(rowData[j], maxNumberLen, position);
                if (j !== rowData.length - 1) {
                    printRow += _fill("", maxNumberLen, position);
                }
            }

            console.log(printRow);
        }
    }


    console.log("自动对齐补全长度为: " + maxNumberLen + ", 对齐方式为: " + (position === "right" ? "右对齐" : (position === "left" ? "左对齐" : "无")));
    const indexSplitRes = index.split(" ");
    console.log(yangHuiTriangleArray[indexSplitRes[0] - 1][indexSplitRes[1] - 1]);
}

/**
 * 功能: 填充使元素等宽
 * @param value         待填充的值
 * @param alignmentLen  对齐长度
 * @param position      对齐方式: left-左对齐, right-右对齐
 * @returns {string|*}
 * @private
 */
function _fill(value, alignmentLen, position) {
    let prefix = "";
    for (let i = 0; i < alignmentLen - (value + "").length; i++) {
        prefix += " ";
    }

    if (position === "left") {
        return value + prefix;
    } else if (position === "right") {
        return prefix + value;
    }

    return value;
}

/**
 * 功能: 生成对应层数的杨辉三角
 * @param numOfLayers   层数
 * @returns {[]}
 * @private
 */
function _generateYangHuiTriangleArray(numOfLayers) {
    let yangHuiTriangleArrayRes = [];
    let parentLeftValue = null;
    let parentRightValue = null;

    for (let i = 1; i <= numOfLayers; i++) {
        let rowData = [];
        let preRowData = i > 1 ? yangHuiTriangleArrayRes[i - 2] : null;

        for (let j = 1; j <= i; j++) {
            // 获取上一行的左右两个值
            if (i === 1) {
                parentLeftValue = null;
                parentRightValue = null;
            } else {
                if (j === 1) {
                    parentLeftValue = null;
                    parentRightValue = 1;
                } else if (j === i) {
                    parentLeftValue = 1;
                    parentRightValue = null;
                } else {
                    parentLeftValue = preRowData[j - 2];
                    parentRightValue = preRowData[j - 1];
                }
            }
            // 获取当前节点的值
            const currentNodeValue = _getYangHuiTriangleNode(j, i, parentLeftValue, parentRightValue);
            rowData.push(currentNodeValue);
        }

        yangHuiTriangleArrayRes.push(rowData);
    }

    return yangHuiTriangleArrayRes;
}

/**
 * 功能: 生成前缀空格
 * @param currentNumOfLayer
 * @param numOfLayers
 * @returns {[]}
 * @private
 */
function _generatePrefixSpace(currentNumOfLayer, numOfLayers) {
    let spaceRes = [];
    for (let i = 0; i < numOfLayers - currentNumOfLayer; i++) {
        spaceRes.push(" ");
    }
    return spaceRes;
}

/**
 * 功能: 校验参数是否合法
 * @param numOfLayers   要打印的杨辉三角层数
 */
function _valid(numOfLayers, index) {
    if (isNaN(numOfLayers)) {
        throw new Error("非法参数: " + numOfLayers + "为无效数字!");
    }
    if (numOfLayers < 1) {
        throw new Error("错误的值: " + numOfLayers + "必须为大于0的整数!");
    }
    if (!/\d+ \d+/.test(index)) {
        throw new Error("错误的index值, 格式为: '数字 数字'");
    }
    const indexSplitRes = index.split(" ");
    if (indexSplitRes[0] < 1) {
        throw new Error("错误的index值: 第1个参数必须大于等于1!");
    }
    if (indexSplitRes[1] < 1 || indexSplitRes[1] > 10000) {
        throw new Error("错误的index值: 第2个参数必须在1~10000之间!");
    }
}

/**
 * 功能: 根据下表和当前层数来获取当前节点的值
 * @param currentIndex          当前遍历下表
 * @param currentNumOfLayer     当前遍历杨辉三角层数
 * @param parentLeftValue       上层左边的值
 * @param parentRightValue      上层右边的值
 * @returns {number|*}
 */
function _getYangHuiTriangleNode(currentIndex, currentNumOfLayer, parentLeftValue, parentRightValue) {
    // 第一个元素为1
    if (currentIndex === 1) {
        return 1;
    }
    // 最后一个元素为1
    if (currentIndex === currentNumOfLayer) {
        return 1;
    }
    return parentLeftValue + parentRightValue;
}

/**
 * 功能: 判断对象是否为无效
 * @param value          判断的对象
 * @returns {boolean}   true: 无效, false: 有效
 */
function isEmpty(value) {
    if (typeof value === "undefined" || value === null) {
        return true;
    }

    if (typeof value === "string") {
        return value === "";
    }

    if (value instanceof Array) {
        return value.length === 0;
    }

    return false;
}

printYangHuiTriangle(NUM_OF_LAYERS, POSITION, AXIAL_SYMMETRY, INDEX);